export class EventBus<EventMap> {
  // eslint-disable-next-line
  private eventHub: Map<string, Set<Function>>;

  constructor() {
    this.eventHub = new Map();
  }

  public on<K extends string & keyof EventMap>(
    eventName: K,
    callback: EventMap[K]
  ) {
    if (!eventName || typeof callback !== "function") return;
    const eventSet = this.eventHub.get(eventName) || new Set();
    eventSet.add(callback);
    this.eventHub.set(eventName, eventSet);
  }

  public emit<K extends string & keyof EventMap>(
    eventName: K,
    payload?: EventMap[K] extends (payload: infer P) => void ? P : never
  ) {
    if (!eventName) return;
    const callBackSet = this.eventHub.get(eventName);
    if (!callBackSet) return;
    if (callBackSet.size === 1) {
      const callBack = [...callBackSet];
      return callBack[0](payload);
    }
    callBackSet.forEach((callBack) => callBack(payload));
  }

  public off<K extends string & keyof EventMap>(
    eventName: K,
    callback: EventMap[K]
  ) {
    if (!eventName || typeof callback !== "function") return;
    const callBackSet = this.eventHub.get(eventName);
    if (!callBackSet) return;
    callBackSet.delete(callback);
  }

  public isSubscribe<K extends string & keyof EventMap>(eventName: K): boolean {
    const eventSet = this.eventHub.get(eventName);
    return !!eventSet && eventSet.size > 0;
  }
}
